#include "ls_audio.h"
#include "ls_trace_common.h"
#include "ls_Internal.h"
#include "shell.h"

pthread_t audio_pid;
audio_data_cb  data_cb = NULL;
SemaphoreHandle_t   audio_sem;


const unsigned char*  internalAudioMap[][2]={
    {scan_qrcode_ok,(const unsigned char*)sizeof(scan_qrcode_ok)},
    {wifi_conenct_ok,(const unsigned char*)sizeof(wifi_conenct_ok)},
    {wifi_conenct_failed,(const unsigned char*)sizeof(wifi_conenct_failed)},
    {audio_reset_ok,(const unsigned char*)sizeof(audio_reset_ok)},
};

// clang-format off
static const uint16_t sin_0db_16point[] = {
    0x0000, 0x30FB, 0x5A81, 0x7640, 0x7FFF, 0x7640, 0x5A81, 0x30FB, 0x0000, 0xCF05, 0xA57F, 0x89C0, 0x8001, 0x89C0, 0xA57F, 0xCF05,
};

static struct bflb_device_s *auadc_hd;
static struct bflb_device_s *auadc_dma_hd;

static struct bflb_device_s *audac_hd;
static struct bflb_device_s *audac_dma_hd;


#define AUADC_SAMPLING_NUM (8 * 1024)
static ATTR_NOCACHE_NOINIT_RAM_SECTION uint16_t record_buff[AUADC_SAMPLING_NUM];


struct bflb_dma_channel_lli_transfer_s transfers_in={
    .src_addr = (uint32_t)DMA_ADDR_AUADC_RDR,
    .dst_addr = (uint32_t)record_buff,
    .nbytes = sizeof(record_buff),
};
static struct bflb_dma_channel_lli_pool_s lli_pool_in[8];


struct bflb_dma_channel_lli_transfer_s transfers_out=
{
   .src_addr = (uint32_t)record_buff,
    .dst_addr = (uint32_t)DMA_ADDR_AUDAC_TDR,
   .nbytes = sizeof(record_buff),
};
static struct bflb_dma_channel_lli_pool_s lli_pool_out[8];



void audio_dma_callback_in(void *arg)
{
    // printf("auadc record end\r\n");

    static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    int32_t ret = xSemaphoreGiveFromISR(audio_sem, &xHigherPriorityTaskWoken);
    if (ret == pdPASS) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }

}


void audio_dma_callback_out(void *arg)
{
//    printf("auadc send end\r\n");  
}

/* ai init */
static void __ls_audio_auadc_gpio_init(void)
{
    struct bflb_device_s *gpio;

    gpio = bflb_device_get_by_name("gpio");


    /* auadc ch0 */
    bflb_gpio_init(gpio, GPIO_PIN_20, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);
    /* auadc ch1 */
    //bflb_gpio_init(gpio, GPIO_PIN_21, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);

    /* auadc ch2 */
    //bflb_gpio_init(gpio, GPIO_PIN_22, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);
    /* auadc ch3 */
    // bflb_gpio_init(gpio, GPIO_PIN_23, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);

    /* auadc ch4 */
    //bflb_gpio_init(gpio, GPIO_PIN_27, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);

    /* auadc ch5 */
    bflb_gpio_init(gpio, GPIO_PIN_28, GPIO_INPUT | GPIO_PULLDOWN | GPIO_SMT_EN | GPIO_DRV_2);
    // bflb_gpio_init(gpio, GPIO_PIN_28, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);

    /* auadc ch6 */
    // bflb_gpio_init(gpio, GPIO_PIN_29, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);
    // /* auadc ch7 */
    // bflb_gpio_init(gpio, GPIO_PIN_30, GPIO_ANALOG | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_2);
}


/* ao gpio init*/
static void  __ls_audio_audac_gpio_init(void)
{
    struct bflb_device_s *gpio;

    gpio = bflb_device_get_by_name("gpio");

    /* audac pwm output mode */
    bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_FUNC_AUDAC_PWM | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
    bflb_gpio_init(gpio, GPIO_PIN_15, GPIO_FUNC_AUDAC_PWM | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);

    // bflb_gpio_init(gpio, GPIO_PIN_22, GPIO_FUNC_AUDAC_PWM | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
    // bflb_gpio_init(gpio, GPIO_PIN_23, GPIO_FUNC_AUDAC_PWM | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);

    // bflb_gpio_init(gpio, GPIO_PIN_27, GPIO_FUNC_AUDAC_PWM | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
    // bflb_gpio_init(gpio, GPIO_PIN_28, GPIO_FUNC_AUDAC_PWM | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);


    bflb_gpio_init(gpio, GPIO_PIN_25, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
    // bflb_gpio_init(gpio, GPIO_PIN_32, GPIO_INPUT | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_0);
    // bflb_gpio_init(gpio, GPIO_PIN_26, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);

    bflb_gpio_set(gpio, GPIO_PIN_25);
    // bflb_gpio_set(gpio, GPIO_PIN_26);

    printf("GPIO_PIN_25:%d",bflb_gpio_read(gpio,GPIO_PIN_25));
    // printf("GPIO_PIN_26:%d",bflb_gpio_read(gpio,GPIO_PIN_26));
}




static void __ls_audio_auadc_dma_init(void)
{
    struct bflb_dma_channel_config_s auadc_dma_cfg;

    auadc_dma_cfg.direction = DMA_PERIPH_TO_MEMORY;
    auadc_dma_cfg.src_req = DMA_REQUEST_AUADC_RX;
    auadc_dma_cfg.dst_req = DMA_REQUEST_NONE;
    auadc_dma_cfg.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    auadc_dma_cfg.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    auadc_dma_cfg.src_burst_count = DMA_BURST_INCR4;
    auadc_dma_cfg.dst_burst_count = DMA_BURST_INCR4;
    auadc_dma_cfg.src_width = DMA_DATA_WIDTH_16BIT;
    auadc_dma_cfg.dst_width = DMA_DATA_WIDTH_16BIT;

    auadc_dma_hd = bflb_device_get_by_name("dma0_ch2");
    bflb_dma_channel_init(auadc_dma_hd, &auadc_dma_cfg);
    bflb_dma_channel_irq_attach(auadc_dma_hd, audio_dma_callback_in, NULL);

    bflb_dma_channel_lli_reload(auadc_dma_hd,lli_pool_in,LS_ARRAY_SIZE(lli_pool_in), &transfers_in, 1);
    //uint32_t dma_lli_cnt=
    //bflb_dma_channel_lli_link_head(auadc_dma_hd, lli_pool_in, dma_lli_cnt);
}


///
static void __ls_audio_audac_dma_init(void)
{
    // uint32_t dma_lli_cnt;
    
    
    struct bflb_dma_channel_config_s audac_dma_cfg;

    audac_dma_cfg.direction = DMA_MEMORY_TO_PERIPH;
    audac_dma_cfg.src_req = DMA_REQUEST_NONE;
    audac_dma_cfg.dst_req = DMA_REQUEST_AUDAC_TX;
    audac_dma_cfg.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    audac_dma_cfg.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    audac_dma_cfg.src_burst_count = DMA_BURST_INCR8;
    audac_dma_cfg.dst_burst_count = DMA_BURST_INCR8;
    audac_dma_cfg.src_width = DMA_DATA_WIDTH_16BIT;
    audac_dma_cfg.dst_width = DMA_DATA_WIDTH_16BIT;

    audac_dma_hd = bflb_device_get_by_name("dma0_ch3");
    bflb_dma_channel_init(audac_dma_hd, &audac_dma_cfg);
    bflb_dma_channel_irq_attach(audac_dma_hd, audio_dma_callback_out, NULL);


    bflb_dma_channel_lli_reload(audac_dma_hd,lli_pool_out,LS_ARRAY_SIZE(lli_pool_out),&transfers_out, 1);
    // bflb_dma_channel_lli_link_head(audac_dma_hd, lli_pool_out, dma_lli_cnt);
}


/// @brief 
/// @param  
static void __ls_audio_auadc_init(void)
{
    /* audio adc config */
    struct bflb_auadc_init_config_s auadc_init_cfg = {
        .sampling_rate = AUADC_SAMPLING_RATE_8K,
        .input_mode = AUADC_INPUT_MODE_ADC,
        .data_format = AUADC_DATA_FORMAT_16BIT,
        .fifo_threshold = 3,
    };

    /* audio adc analog config */
    struct bflb_auadc_adc_init_config_s auadc_analog_init_cfg = {
        .auadc_analog_en = true,
        .adc_mode = AUADC_ADC_MODE_AUDIO,
        .adc_pga_mode = AUADC_ADC_PGA_MODE_AC_DIFFER,
        .adc_pga_posi_ch = AUADC_ADC_ANALOG_CH_0,
        .adc_pga_nega_ch = AUADC_ADC_ANALOG_CH_5,
        .adc_pga_gain = 42,
    };



    /* clock config */
    GLB_Config_AUDIO_PLL_To_491P52M();
    GLB_PER_Clock_UnGate(GLB_AHB_CLOCK_AUDIO);

    /* auadc init */
    auadc_hd = bflb_device_get_by_name("auadc");
    bflb_auadc_init(auadc_hd, &auadc_init_cfg);
    bflb_auadc_adc_init(auadc_hd, &auadc_analog_init_cfg);
    /* set volume */
    bflb_auadc_feature_control(auadc_hd, AUADC_CMD_SET_VOLUME_VAL, (size_t)(10));
    /* auadc enable dma */
    bflb_auadc_link_rxdma(auadc_hd, true);
}


/* audio dac init */
static void __ls_audio_audac_init(void)
{
    struct bflb_audac_init_config_s audac_init_cfg = {
        .sampling_rate = AUDAC_SAMPLING_RATE_8K,
        .output_mode = AUDAC_OUTPUT_MODE_PWM,
        .source_channels_num = AUDAC_SOURCE_CHANNEL_SINGLE,
        .mixer_mode = AUDAC_MIXER_MODE_ONLY_L,
        .data_format = AUDAC_DATA_FORMAT_16BIT,
        .fifo_threshold = 7,
    };

    struct bflb_audac_volume_config_s audac_volume_cfg = {
        .mute_ramp_en = true,
        .mute_up_ramp_rate = AUDAC_RAMP_RATE_FS_8,
        .mute_down_ramp_rate = AUDAC_RAMP_RATE_FS_8,
        .volume_update_mode = AUDAC_VOLUME_UPDATE_MODE_RAMP,
        .volume_ramp_rate = AUDAC_RAMP_RATE_FS_8,
        .volume_zero_cross_timeout = AUDAC_RAMP_RATE_FS_8,
    };

    /* clock cfg */
    GLB_Config_AUDIO_PLL_To_491P52M();
    GLB_PER_Clock_UnGate(GLB_AHB_CLOCK_AUDIO);

    /* audac init */
    audac_hd = bflb_device_get_by_name("audac");
    bflb_audac_init(audac_hd, &audac_init_cfg);
    bflb_audac_feature_control(audac_hd, AUDAC_CMD_SET_VOLUME_VAL, (size_t)(-10));
    bflb_audac_volume_init(audac_hd, &audac_volume_cfg);
    /* audac enable dma */
    bflb_audac_link_rxdma(audac_hd, true);
}



/// @brief 
static void* ls_audio_audio_done_proc(void *p)
{
    while(1)
    {
        xSemaphoreTake(audio_sem,portMAX_DELAY);
        if(data_cb)
        {
            // bflb_dma_channel_lli_reload(audac_dma_hd,lli_pool_out,LS_ARRAY_SIZE(lli_pool_out),&transfers_out, 1);
            // bflb_dma_channel_start(audac_dma_hd);
            data_cb((const char *)record_buff,sizeof(record_buff));
        }
        bflb_dma_channel_lli_reload(auadc_dma_hd, lli_pool_in,LS_ARRAY_SIZE(lli_pool_in), &transfers_in, 1);
        bflb_dma_channel_start(auadc_dma_hd);
    }
    return NULL;
}

/********************************************************************************************************/

/// @brief 
void ls_audio_init(audio_data_cb cb)
{

    //in
    data_cb = cb;
    audio_sem = xSemaphoreCreateBinary();
    pthread_create(&audio_pid,NULL,ls_audio_audio_done_proc,NULL);
    /* gpio init */
    __ls_audio_auadc_gpio_init();
    /* auadc init */
    __ls_audio_auadc_init();
    /* dma init and start */
    __ls_audio_auadc_dma_init();
    //
    bflb_dma_channel_start(auadc_dma_hd);
    /* auadc start */
    bflb_auadc_feature_control(auadc_hd, AUADC_CMD_RECORD_START, 0);

    //out
    /* gpio init */
    __ls_audio_audac_gpio_init();
    /* auadc init */
    __ls_audio_audac_init();
    //
    __ls_audio_audac_dma_init();
    // //
    // bflb_dma_channel_start(audac_dma_hd);
    //
    bflb_audac_feature_control(audac_hd, AUDAC_CMD_PLAY_START, 0);
    //
    bflb_audac_feature_control(audac_hd, AUDAC_CMD_SET_MUTE, false);

}


///
void ls_audio_play_internal(AUDIO_TYPE_E e)
{
    LS_TRACE_DEBUG("audio_reset_ok:%p internalAudioMap[e][0]:%p",audio_reset_ok,internalAudioMap[e][0]);
    LS_TRACE_DEBUG("internalAudioMap[e][1]:%d",internalAudioMap[e][1]);
    transfers_out.src_addr = (uint32_t)internalAudioMap[e][0];
    transfers_out.nbytes   = (uint32_t)internalAudioMap[e][1]; 
    bflb_dma_channel_lli_reload(audac_dma_hd,lli_pool_out,LS_ARRAY_SIZE(lli_pool_out),&transfers_out, 1);
    bflb_dma_channel_start(audac_dma_hd);   
}


///需要等待DMA发送完成
void ls_audio_play_data(const char *data,uint16_t len)
{


}



void play_internal(void *param)
{
    ls_audio_play_internal(E_NET_CONENCT_ERROR);
}

SHELL_CMD_EXPORT_ALIAS(play_internal,play_internal,cmd_play_internal);